/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package jogo;

import java.io.DataInputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Vector;
import util.Constantes;
import util.Util;

/**
 *
 * @author FAST
 */
public class JogoServidor {

    // ATRIBUTOS DE CONTROLE DO JOGO ///////////////////////////////////////////
    private int status; // Identificador do estado atual do jogo

    private int rodada; // Identificador da rodada atual

    private int jogadorDaVez; // Identificar de quem deve jogar

    private Jogador[] jogadores; // array de jogadores da partida

    private Vector nomeJogadores; // vector dos nome dos jogadores

    private Vector ultimaRodadaPartida;
    
    private Vector jogadas;
    private int cabecaDireita;
    private int cabecaEsquerda;
    private int escoreEquipe1;
    private int escoreEquipe2;
    private Peca pecaComeca;
    private int quemComeca;
    private int partida;
    private int tocou;
    private boolean novaPartida = true;

    private int nivelDificuldadeBot = 0;
    
    public JogoServidor() {
        this.jogadas = new Vector(100);
        this.jogadores = new Jogador[4];
        this.nomeJogadores = new Vector(4);
        this.ultimaRodadaPartida = new Vector(10);
        this.status = Constantes.STATUS_ESPERANDO_INICIAR;
    }

    public int getStatus() {
        return this.status;
    }

    public Vector gerarStatusIniciando(String nome) {
        System.out.println("JogoServidor.gerarStatusIniciando();");

        Vector resposta = new Vector();
        resposta.addElement(new Integer(Constantes.STATUS_ESPERANDO_INICIAR));

        boolean noJogo = this.nomeJogadores.contains(nome);
        resposta.addElement(new Boolean(noJogo));
        resposta.addElement(new Integer(this.nomeJogadores.size()));

        if (noJogo) {
            for (Enumeration e = this.nomeJogadores.elements(); e.hasMoreElements();) {
                String s = (String) e.nextElement();
                resposta.addElement(s);
            }
        }
        return resposta;
    }

    public void conectarJogador(String nome) {
        System.out.println("JogoServidor.conectarJogador();");
        if (this.nomeJogadores.size() < 4 && !this.nomeJogadores.contains(nome)) {
            this.nomeJogadores.addElement(nome);
            System.out.println("JogoServidor.conectarJogador(): Jogador " + nome + " conectado");
        }
    }

    // Metodo chamado pela tela do usario que eh servidor para inicializar a partida
    public void comecarPartida() {
        if (this.status == Constantes.STATUS_ESPERANDO_INICIAR) {
            Vector[] pecas = Util.sortearJogo();

            int pos = 0;
            // Cria os objectos jogadores com os que se conectaram
            for (Enumeration e = this.nomeJogadores.elements(); e.hasMoreElements();) {
                String nome = (String) e.nextElement();
                this.jogadores[pos] = new Jogador(nome, pecas[pos], false);
                pos++;
            }

            // Preenche os espaços vagos com bots ate obter 4 jogadores
            while (pos < 4) {
                int i = Util.RANDOM.nextInt(Constantes.nomeJogadores.length);
                String nome = Constantes.nomeJogadores[i] + "(BOT)";
                if (!this.nomeJogadores.contains(nome)) {
                    this.nomeJogadores.addElement(nome);
                    this.jogadores[pos] = new Jogador(nome, pecas[pos], true);
                    pos++;
                }
            }

            this.rodada = 1;
            this.partida = 0;
            this.escoreEquipe1 = 0;
            this.escoreEquipe2 = 0;
            this.jogadas.addElement(new Jogada());

            this.quemTemMaiorCarrocaComeca();
            this.checarBotComeca();

            this.status = Constantes.STATUS_ESPERANDO_JOGADA;
        }
    }

    private void quemTemMaiorCarrocaComeca() {
        System.out.println("JogoServidor.jogaPrimeiraRodada();");
        for (int maiorPeca = 6; maiorPeca >= 0; maiorPeca--) {
            Peca carrocao = new Peca(maiorPeca, maiorPeca);
            for (int pos = 0; pos < 4; pos++) {
                Jogador jogadorAtual = this.jogadores[pos];
                if (jogadorAtual.temPeca(carrocao)) {
                    this.pecaComeca = carrocao;
                    this.quemComeca = pos;
                    return;
                }
            }
        }
    }

    private void checarBotComeca() {
        Jogador jogadorAtual = this.jogadores[this.quemComeca];
        if (jogadorAtual.ehMaquina()) {
            System.out.println("JogoServidor.checarBotComeca(): bot comecou");
            this.jogadorDaVez = this.getPosicaoJogador(jogadorAtual);
            this.jogarPeca(new Jogada(jogadorAtual, this.pecaComeca, Constantes.PECA_INICIAL));
        }
    }

    private void jogarPeca(Jogada jogada) {
        if(!jogada.ehValida(this.cabecaDireita, this.cabecaEsquerda)) {
            return;
        }
        
        // Atualiza a cabeça onde se esta jogando
        if (jogada.getLado() == Constantes.LADO_DIREITO) {
            if (jogada.getPeca().getValor1() == this.cabecaDireita) {
                this.cabecaDireita = jogada.getPeca().getValor2();
            } else {
                this.cabecaDireita = jogada.getPeca().getValor1();
            }
        } else if (jogada.getLado() == Constantes.LADO_ESQUERDO) {
            if (jogada.getPeca().getValor1() == this.cabecaEsquerda) {
                this.cabecaEsquerda = jogada.getPeca().getValor2();
            } else {
                this.cabecaEsquerda = jogada.getPeca().getValor1();
            }
        } else {
            // Se eh primeira rodada            
            this.cabecaDireita = jogada.getPeca().getValor1();
            this.cabecaEsquerda = jogada.getPeca().getValor2();
        }

        // Atualiza a peca jogada
        this.rodada++;
        this.jogadas.addElement(jogada);
        jogada.getJogador().jogarPeca(jogada.getPeca());
        System.out.print("JogoServidor.jogarPeca(): jogada realizada com sucesso - ");
        System.out.println(this.getPosicaoJogador(jogada.getJogador()) + ": " + jogada.getPeca().toString());

        // Verifica fim do jogo
        if (jogada.getJogador().getPecas().size() > 0) {
            novaPartida = false;
            this.finalizarRodada();
        } else {
            novaPartida = true;
            this.acabarPartida(jogada.getPeca());
        }
    }

    private void finalizarRodada() {
        this.jogadorDaVez = (this.jogadorDaVez + 1) % 4;
        Jogador jogadorAtual = this.jogadores[this.jogadorDaVez];

        if (jogadorAtual.podeJogar(this.cabecaDireita, this.cabecaEsquerda) != null) {
            this.tocou = 0;
            this.checarVezDoBot();
        } else {
            this.tocou++;
            this.rodada++;
            this.jogadas.addElement(new Jogada());            
            if (this.tocou == 4) {
                this.recomecarPartida();
                this.quemTemMaiorCarrocaComeca();
            } else {
                this.finalizarRodada();
            }
        }
    }

    private void checarVezDoBot() {
        Jogador jogadorAtual = this.jogadores[this.jogadorDaVez];
        if (jogadorAtual.ehMaquina()) {
            System.out.println("JogoServidor.checarVezDoBot(): vez do bot");
            this.jogarPeca(jogadorAtual.getJogadaDaMaquina(this.cabecaDireita, this.cabecaEsquerda,
                    this.nivelDificuldadeBot,this.jogadas));
        }
    }

    private void acabarPartida(Peca pecaBatida) {
        this.quemComeca = 4 + (this.jogadorDaVez % 2);
        int pontos = pecaBatida.getPontosBatida(this.cabecaDireita, this.cabecaEsquerda);

        if (this.quemComeca == Constantes.EQUIPE1) {
            this.escoreEquipe1 += pontos;
        }
        if (this.quemComeca == Constantes.EQUIPE2) {
            this.escoreEquipe2 += pontos;
        }
        this.recomecarPartida();
    }

    private void recomecarPartida() {
        this.ultimaRodadaPartida.addElement(new Integer(this.rodada - 1));
        Vector[] pecas = Util.sortearJogo();
        for (int i = 0; i < 4; i++) {
            this.jogadores[i].setPecas(pecas[i]);
        }
        this.partida++;
        this.rodada ++;
        this.jogadas.addElement(new Jogada());        
        this.status = Constantes.STATUS_ESPERANDO_JOGADA;
        this.checarEquipeBotComeca();
    }
    
    private void checarEquipeBotComeca() {
        if(this.quemComeca == Constantes.EQUIPE1) {
            if(this.jogadores[0].ehMaquina() && this.jogadores[2].ehMaquina()) {
                Jogador jogador = this.jogadores[0];
                Peca peca = (Peca)jogador.getPecas().elementAt(0);
                this.jogadorDaVez = this.getPosicaoJogador(jogador);
                this.jogarPeca(new Jogada(jogador, peca, Constantes.PECA_INICIAL));
            }
        } else if(this.quemComeca == Constantes.EQUIPE2) {
            if(this.jogadores[1].ehMaquina() && this.jogadores[3].ehMaquina()) {
                Jogador jogador = this.jogadores[1];
                Peca peca = (Peca)jogador.getPecas().elementAt(0);
                this.jogadorDaVez = this.getPosicaoJogador(jogador);
                this.jogarPeca(new Jogada(jogador, peca, Constantes.PECA_INICIAL));
            }            
        }
    }

    public Vector gerarStatusJogada(String nome, int partida, int rodada) {
        Vector resposta = new Vector();
        resposta.addElement(new Integer(Constantes.STATUS_ESPERANDO_JOGADA));
        resposta.addElement(new Integer(this.partida));
        resposta.addElement(new Integer(this.jogadorDaVez));
 
        for (int i = 0; i < Constantes.N_MAX_STATUS && rodada < this.rodada; i++, rodada++) {                      
            if (rodada == this.getPrimeiraRodadaPartida(partida)) {
                resposta.addElement(new Integer(Constantes.STATUS_JOGADOR_INICIANDO));
                resposta.addElement(new Integer(rodada));
                int posicao = this.getPosicaoJogador(nome);
                resposta.addElement(new Integer(posicao));
                Vector pecas = this.jogadores[posicao].getPecas();
                for (Enumeration e = pecas.elements(); e.hasMoreElements();) {
                    Peca peca = (Peca) e.nextElement();
                    resposta.addElement(new Integer(peca.getValor1()));
                    resposta.addElement(new Integer(peca.getValor2()));
                }
            } else {
                resposta.addElement(new Integer(Constantes.STATUS_JOGADA));
                resposta.addElement(new Integer(rodada));

                Jogada jogada = (Jogada) this.jogadas.elementAt(rodada);
                resposta.addElement(new Boolean(jogada.foiToque()));
                if (!jogada.foiToque()) {
                    resposta.addElement(new Integer(this.getPosicaoJogador(jogada.getJogador())));
                    resposta.addElement(new Integer(jogada.getLado()));
                    resposta.addElement(new Integer(jogada.getPeca().getValor1()));
                    resposta.addElement(new Integer(jogada.getPeca().getValor2()));
                }                
                if(partida < this.partida && rodada == this.getUltimaRodadaPartida(partida)) {
                    partida++;
                }
            }
        }

        resposta.addElement(new Integer(Constantes.STATUS_FIM));
        return resposta;
    }

    private int getUltimaRodadaPartida(int partida) {
        Integer inteiro = (Integer)this.ultimaRodadaPartida.elementAt(partida);
        return inteiro.intValue();
    }
    
    private int getPrimeiraRodadaPartida(int partida) {
        if(partida == 0) return 0;
        else return this.getUltimaRodadaPartida(partida-1) + 1;
    }
    
    private int getPosicaoJogador(String nome) {
        return this.nomeJogadores.indexOf(nome);
    }

    private int getPosicaoJogador(Jogador jogador) {
        return this.getPosicaoJogador(jogador.getNome());
    }
    
    public void realizarJogada(DataInputStream dados) throws IOException {
        System.out.println("JogoServidor.realizarJogada();");

        String nome = dados.readUTF();
        int lado = dados.readInt();
        Peca peca = new Peca(dados.readInt(), dados.readInt());
        Jogador jogadorAtual = this.jogadores[this.jogadorDaVez];
        int posicao = this.getPosicaoJogador(nome);

        if (this.rodada == this.getPrimeiraRodadaPartida(this.partida) + 1) {
            if ((posicao == this.quemComeca && this.pecaComeca.equals(peca)) ||
                    (this.quemComeca >= 4 && (posicao == this.quemComeca - 2 || posicao == this.quemComeca - 4))) {
                this.jogadorDaVez = posicao;
                this.jogarPeca(new Jogada(jogadorAtual, peca, Constantes.PECA_INICIAL));
            }
        } else {
            if (this.jogadorDaVez == posicao) {
                this.jogarPeca(new Jogada(jogadorAtual, peca, lado));
            }
        }
    }

    public void setNivelDificuldadeBot(int nivelDificuldadeBot) {
        this.nivelDificuldadeBot = nivelDificuldadeBot;
    }
    
    
    
}
